package antcraft;

public class PheromoneMap {
	static final int n_pheromoneTypes = 5;
	
	/**
	 * m_pheromoneGrid: 3D array of Vector2D objects, where the first and
	 * second indexes are the X and Y coordinate of the box and the third
	 * index is the type of pheromone.  Int m_gridSize represents the size
	 * of each box on a side, and is used to translate between game
	 * coordinates and the proper box.
	 **/
	private Vector2D m_pheromoneGrid[][][];
	public int m_mapWidth, m_mapHeight;
	private MapVisualization m_mapVisualization;

	/**
	 * decayRate and diffuseRate: Array of doubles where each entry
	 * represents the decay or diffusion rate of the pheromone type
	 * corresponding to the array index.
	 **/
	static double decayRate[];
	static double diffuseRate[];

	/**
	 * Constructor: Takes in a grid size and a map width and height.
	 * Assigns memory to the vectors and such.
	 **/
	public PheromoneMap( int mapWidth, int mapHeight ) {
		m_pheromoneGrid = new Vector2D[mapWidth][mapHeight][n_pheromoneTypes];
		m_mapWidth = mapWidth;
		m_mapHeight = mapHeight;
		for( int i = 0; i < mapWidth; i++ )
			for( int j = 0; j < mapHeight; j++ )
				for( int k = 0; k < n_pheromoneTypes; k++ )
					m_pheromoneGrid[i][j][k] = new Vector2D();
		
		decayRate = new double[n_pheromoneTypes];
		diffuseRate = new double[n_pheromoneTypes];
		
		for( int i = 0; i < n_pheromoneTypes; i++ ) {
			decayRate[i] = 0.95;
			diffuseRate[i] = 0.98;
		}
		
		m_mapVisualization = new MapVisualization( this );
	}

	/**
	 * When an ant calls placePheromone, find the vector it should be
	 * interacting with based on its xPos and yPos and the type, then
	 * add a new vector represented by strength and direction.
	 **/
	public void placePheromone( int xPos, int yPos, int type, double strength,
			double direction ) {
		double xComponent = Math.cos( direction ) * strength;
		double yComponent = Math.sin( direction ) * strength;
		Vector2D pheromoneVector = new Vector2D( xComponent, yComponent );
		m_pheromoneGrid[xPos][yPos][type] =
			m_pheromoneGrid[xPos][yPos][type].add( pheromoneVector );
	}

	/**
	 * getMagnitude and getDirection should first translate from the ant's
	 * xPos and yPos to X and Y indexes then return the magnitude or
	 * direction of the vector at that point.
	 **/
	public double getMagnitude( int xPos, int yPos, int type ) {
		return m_pheromoneGrid[xPos][yPos][type].magnitude();
	}
	public double getDirection( int xPos, int yPos, int type ) {
		return m_pheromoneGrid[xPos][yPos][type].direction();
	}

	/**
	 * decay and diffuse: Decay causes the pheromones to decay at a
	 * particular rate based on the type.  Diffuse causes the pheromones
	 * to Gaussian blur with their neighbors.  In both cases, pass the
	 * number of time-ticks that have passed, and do that number of
	 * iterations.
	 **/
	public void decay( int type, int deltaT ) {
		double decay = Math.pow( decayRate[type], deltaT );
		
		for( int i = 0; i < m_mapWidth; i++ )
			for( int j = 0; j < m_mapHeight; j++ )
				m_pheromoneGrid[i][j][type] =
					m_pheromoneGrid[i][j][type].multiply( decay );
	}
	public void diffuse( int type, int deltaT ) {
		double diffuse = Math.pow( diffuseRate[type], deltaT );
		Vector2D weightedNeighborSum;
		Vector2D weightedSelf;
		double numNeighbors;
		
		Vector2D[][] cloneMap = new Vector2D[m_mapWidth][m_mapHeight];
		
		for( int i = 0; i < m_mapWidth; i++ )
			for( int j = 0; j < m_mapHeight; j++ )
				cloneMap[i][j] = m_pheromoneGrid[i][j][type];
		
		for( int i = 0; i < m_mapWidth; i++ )
			for( int j = 0; j < m_mapHeight; j++ ) {
				weightedSelf = cloneMap[i][j].multiply( diffuse );
				weightedNeighborSum = new Vector2D();
				numNeighbors = 0;
				
				if( i > 0 && j > 0 ) {
					weightedNeighborSum = weightedNeighborSum.add( cloneMap[i-1][j-1] );
					numNeighbors += 1;
				}
				if( i > 0 ) {
					weightedNeighborSum = weightedNeighborSum.add( cloneMap[i-1][j] );
					numNeighbors += 1;
				}
				if( i > 0 && j < m_mapHeight - 1 ) {
					weightedNeighborSum = weightedNeighborSum.add( cloneMap[i-1][j+1] );
					numNeighbors += 1;
				}
				if( j > 0 ) {
					weightedNeighborSum = weightedNeighborSum.add( cloneMap[i][j-1] );
					numNeighbors += 1;
				}
				if( j < m_mapHeight - 1 ) {
					weightedNeighborSum = weightedNeighborSum.add( cloneMap[i][j+1] );
					numNeighbors += 1;
				}
				if( i < m_mapWidth - 1 && j > 0 ) {
					weightedNeighborSum = weightedNeighborSum.add( cloneMap[i+1][j-1] );
					numNeighbors += 1;
				}
				if( i < m_mapWidth - 1 ) {
					weightedNeighborSum = weightedNeighborSum.add( cloneMap[i+1][j] );
					numNeighbors += 1;
				}
				if( i < m_mapWidth - 1 && j < m_mapHeight - 1 ) {
					weightedNeighborSum = weightedNeighborSum.add( cloneMap[i+1][j+1] );
					numNeighbors += 1;
				}
				weightedNeighborSum = weightedNeighborSum.multiply( 1 / numNeighbors );
				weightedNeighborSum = weightedNeighborSum.multiply( 1 - diffuse );
				
				m_pheromoneGrid[i][j][type] = weightedSelf.add( weightedNeighborSum );
			}
	}
}
